﻿using System.Data.SqlClient;
using System;
using System.Data;
using System.Text;
using System.Text.RegularExpressions;
using AccesoDatos.DTO.Base;
using System.IO;
using System.Drawing;
namespace AccesoDatos.DAO.Base
{
    /// <summary>
    /// Contiene propiedades y métodos que proveen información a los DAO
    /// </summary>
    public abstract class BaseDAO
    {
        #region Campos

        /// <summary>
        /// objeto conexión de la base de datos de tramitaciones
        /// </summary>
        private SqlConnection conexionIntegra;

        /// <summary>
        /// Cadena de conexión a la BBDD de tramitaciones
        /// </summary>
        private static string cadenaConexionIntegra;

        #endregion

        #region Propiedades

        /// <summary>
        /// Devuelve la cadena de conexion
        /// </summary>
        public string GetCadenaConexionIntegra 
        {
            get { return cadenaConexionIntegra = "Server=CR-PC;Database=Integra;Trusted_Connection=True; MultipleActiveResultSets=true"; }
        }

        /// <summary>
        /// Retorna un tipo string
        /// </summary>
        protected Type GetTypeString
        {
            get
            {
                return Type.GetType("System.String");
            }
        }

        /// <summary>
        /// Retorna un tipo Int32
        /// </summary>
        protected Type GetTypeInt32
        {
            get
            {
                return Type.GetType("System.Int32");
            }
        }

        /// <summary>
        /// Retonra un Int32 con posiblidad de valores nulos.
        /// </summary>
        protected Type GetTypeSqlInt32
        {
            get
            {
                return typeof(System.Data.SqlTypes.SqlInt32);
            }
        }

        /// <summary>
        /// Retorna un tipo DateTime
        /// </summary>
        protected Type GetTypeDateTime
        {
            get
            {
                return Type.GetType("System.DateTime");
            }
        }

        /// <summary>
        /// Retorna un tipo chars
        /// </summary>
        protected Type GetTypeChar
        {
            get
            {
                return Type.GetType("System.Char");
            }
        }

        /// <summary>
        /// Retorna un tipo boolean
        /// </summary>
        protected Type GetTypeBoolean
        {
            get
            {
                return Type.GetType("System.Boolean");
            }
        }

        /// <summary>
        /// Retorna la conexión con Integra
        /// </summary>
        protected SqlConnection ConexionIntegra
        {
            get
            {
                if (conexionIntegra == null)
                {
                    conexionIntegra = this.CrearConexion(GetCadenaConexionIntegra);
                }
                else
                {
                    // puede darse que el objeto esté instanciado pero la conexión se haya cerrado
                    if (conexionIntegra.State == ConnectionState.Closed)
                    {
                        // dejamos a null la conexión
                        conexionIntegra = null;

                        // la volvemos a crear
                        conexionIntegra = this.CrearConexion(cadenaConexionIntegra);
                    }
                }
                return conexionIntegra;
            }
        }

        #endregion

        #region Constructores

        /// <summary>
        /// constructor de la clase abstracta.
        /// </summary>
        public BaseDAO()
        {
            //
            // TODO: Agregar aquí la lógica del constructor
            //
        }

        #endregion

        #region Métodos

        /// <summary>
        /// Crea una nueva conexión a una base de datos
        /// </summary>
        /// <param name="cadenaConexion">Cadena de conexión a la base de datos</param>
        /// <returns>Retorna un objeto SqlConection abierto</returns>
        private SqlConnection CrearConexion(String cadenaConexion)
        {

            SqlConnection con = new SqlConnection(cadenaConexion);
            con.Open();
            return con;
        }

        /// <summary>
        /// Si el datareader está abierto lo cierra
        /// </summary>
        /// <param name="dr">DataReader a cerrar</param>
        protected void CerrarDataReader(SqlDataReader dr)
        {
            if (dr != null)
            {
                dr.Close();
            }
        }

        #region Métodos para obtener de un DataReader

        /// <summary>
        /// Método para ayudar a obtener un valor DateTime de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>fecha del datareader</returns>
        protected DateTime GetDateTimeFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            return DateTime.Parse(dr[nombreColumna].ToString());
        }

        /// <summary>
        /// Método para ayudar a obtener un valor double de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>valor del datareader</returns>
        protected double GetDoubleFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            return Double.Parse(dr[nombreColumna].ToString());
        }

        /// <summary>
        /// Método para ayudar a obtener un valor DateTime nulable de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>fecha del datareader, si es nula retorna un null, si la fecha existe retorna
        /// un datetime con la fecha</returns>
        protected DateTime? GetNullableDateTimeFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            DateTime? fecha;
            String txt = dr[nombreColumna].ToString();

            if (String.IsNullOrEmpty(txt))
            {
                fecha = null;
            }
            else
            {
                fecha = DateTime.Parse(txt);
            }

            return fecha;
        }

        /// <summary>
        /// Método para ayudar a obtener un valor double nulable de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>valor del datareader, si es nulo retorna un null</returns>
        protected double? GetNullableDoubleFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            double? valor;
            String txt = dr[nombreColumna].ToString();

            if (String.IsNullOrEmpty(txt))
            {
                valor = null;
            }
            else
            {
                valor = Double.Parse(txt);
            }

            return valor;
        }

        /// <summary>
        /// Método para ayudar a obtener un valor float nulable de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>valor del datareader, si es nulo retorna un null</returns>
        protected float? GetNullableFloatFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            float? valor;
            String txt = dr[nombreColumna].ToString();

            if (String.IsNullOrEmpty(txt))
            {
                valor = null;
            }
            else
            {
                valor = float.Parse(txt);
            }

            return valor;
        }

        /// <summary>
        /// Método para ayudar a obtener un valor entero de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>entero del datareader</returns>
        protected int GetIntFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            return Int32.Parse(dr[nombreColumna].ToString());
        }

        /// <summary>
        /// Método para ayudar a obtener un char nullable de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>char del datareader</returns>
        protected char? GetNullableCharFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            if (dr[nombreColumna].GetType().Equals(System.DBNull.Value.GetType()))
            {
                return null;
            }
            else
            {
                return Char.Parse(dr[nombreColumna].ToString());
            }
        }

        /// <summary>
        /// Método para ayudar a obtener un valor entero nullable de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>entero del datareader</returns>
        protected int? GetNullableIntFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            if (dr[nombreColumna].GetType().Equals(System.DBNull.Value.GetType()))
            {
                return Int32.MinValue;
            }
            else
            {
                return Int32.Parse(dr[nombreColumna].ToString());
            }
        }

        /// <summary>
        /// Método para ayudar a obtener un valor bool nullable de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>entero del datareader</returns>
        protected bool? GetNullableBoolFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            if (dr[nombreColumna].GetType().Equals(System.DBNull.Value.GetType()))
            {
                return null;
            }
            else
            {
                return Boolean.Parse(dr[nombreColumna].ToString());
            }
        }

        /// <summary>
        /// Metodo para ayuda a obtener un string de un datareader
        /// </summary>
        /// <param name="dr">Data reader</param>
        /// <param name="nombreColumna">Nombre de la columna</param>
        /// <returns></returns>
        protected string GetStringFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            return dr[nombreColumna].ToString();
        }

        /// <summary>
        /// Funcion que obtiene un dato de tipo byte[]
        /// </summary>
        /// <param name="dr">Data Reader</param>
        /// <param name="nombreColumna">Nombre de la columna</param>
        /// <returns></returns>
        protected byte[] GetImageFromDataReader(SqlDataReader dr, string nombreColumna) 
        {

              return (byte[])dr[nombreColumna];
        }

    

        //TODO: Comprobar usabilidad de este metodo
        ///// <summary>
        ///// Metodo para ayuda a obtener un XmlDocument de un datareader
        ///// </summary>
        ///// <param name="dr">Data reader</param>
        ///// <param name="nombreColumna">Nombre de la columna</param>
        ///// <returns></returns>
        //protected System.Xml.XmlDocument GetXmlDocumentFromDataReader(SqlDataReader dr, string nombreColumna)
        //{
        //    XmlDocument doc = new XmlDocument();
        //    SqlXml mixml = dr.GetSqlXml(dr.GetOrdinal(nombreColumna));
        //    if (mixml.IsNull)
        //    {
        //        return null;
        //    }
        //    doc.LoadXml(mixml.Value);
        //    return doc;
        //}

        /// <summary>
        /// Método para ayudar a obtener un char de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns></returns>
        protected char GetCharFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            return Char.Parse(dr[nombreColumna].ToString());
        }

        /// <summary>
        /// Método para ayudar a obtener un valor entero corto de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>entero del datareader</returns>
        protected short GetShortFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            return short.Parse(dr[nombreColumna].ToString());
        }

        /// <summary>
        /// Método para ayudar a obtener un valor entero corto nullable de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>entero del datareader</returns>
        protected short? GetNullableShortFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            if (dr[nombreColumna].GetType().Equals(System.DBNull.Value.GetType()))
            {
                return null;
            }
            else
            {
                return short.Parse(dr[nombreColumna].ToString());
            }
        }

        /// <summary>
        /// Método para ayudar a obtener un valor booleanos de un datareader
        /// </summary>
        /// <param name="dr">datareader</param>
        /// <param name="nombreColumna">nombre de la columna</param>
        /// <returns>valor del datareader</returns>
        protected bool GetBoolFromDataReader(SqlDataReader dr, string nombreColumna)
        {
            return Boolean.Parse(dr[nombreColumna].ToString());
        }


        #endregion

        #region Métodos para introducir a la Base de Datos

        /// <summary>
        /// Devuelve una double o DBNull según el parametro pasado.
        /// </summary>
        /// <param name="nullable">Valor double</param>
        /// <returns>Nulo o el valor double</returns>
        protected object GetSqlValue(double? nullable)
        {
            if (nullable == null)
            {
                return System.Data.SqlTypes.SqlDouble.Null;
            }
            else
            {
                return nullable.Value;
            }
        }

        /// <summary>
        /// Devuelve una cadena o DBNull según el parametro pasado.
        /// </summary>
        /// <param name="nullable">cadena de texto</param>
        /// <returns>Nulo o la cadena</returns>
        protected object GetSqlValue(string nullable)
        {
            if (String.IsNullOrEmpty(nullable))
            {
                return System.Data.SqlTypes.SqlString.Null;
            }
            else
            {
                return (string)nullable;
            }
        }

        /// <summary>
        /// Devuelve un entero o DBNull según el parametro pasado.
        /// </summary>
        /// <param name="nullable">Entero nullable</param>
        /// <returns>Nulo o el entero</returns>
        protected object GetSqlValue(int? nullable)
        {
            if (nullable == null)
            {
                return System.Data.SqlTypes.SqlInt32.Null;
            }
            else
            {
                return nullable.Value;
            }
        }

        /// <summary>
        /// Devuelve un DateTime o DBNull según el parametro pasado.
        /// </summary>
        /// <param name="nullable">DateTime nullable</param>
        /// <returns>Nulo o el entero</returns>
        protected object GetSqlValue(DateTime? nullable)
        {
            if (nullable == null)
            {
                return System.Data.SqlTypes.SqlDateTime.Null;
            }
            else
            {
                return nullable.Value;
            }
        }

        /// <summary>
        /// Devuelve un Bool o DBNull según el parametro pasado.
        /// </summary>
        /// <param name="nullable">DateTime nullable</param>
        /// <returns>Nulo o el entero</returns>
        protected object GetSqlValue(bool? nullable)
        {
            if (nullable == null)
            {
                return System.Data.SqlTypes.SqlBoolean.Null;
            }
            else
            {
                return nullable.Value;
            }
        }


        #endregion

        #region Metodos para el trabajo con imagenes en la base de datos

        /// <summary>
        /// Funcion que apartir de una cadena obtiene una Imagen compatible con el formato de la BD
        /// </summary>
        /// <param name="cadena">Contenedor de los parametros del WCF</param>
        /// <returns>Imagen para la BD</returns>
        protected byte[] String2Image(String cadena)
        {
            System.Text.ASCIIEncoding codificador = new System.Text.ASCIIEncoding();
            byte[] bytes = codificador.GetBytes(cadena);

            //if (bytes == null) return null;
            ////
            //MemoryStream ms = new MemoryStream(bytes);
            //Bitmap bm = null;
            //try
            //{
            //    bm = new Bitmap(ms);
            //}
            //catch (Exception ex)
            //{
            //    throw new DAOException(ex);
            //}
            return bytes;
        }

        /// <summary>
        /// Funcion que obtiene una cadena de caracteres a partir de una Imagen
        /// </summary>
        /// <param name="img">Objeto image obtenido de la base de datos</param>
        /// <returns>Cadena de texto con la imagen codificada</returns>
        protected String Image2String(byte[] cad) 
        {
            string cadena = "";
            if (cad != null)
            {
                System.Text.ASCIIEncoding codificador = new System.Text.ASCIIEncoding();
                cadena = codificador.GetString(cad);
            }
            return cadena;
        }


        #endregion


        /// <summary>
        /// Devuelve un código personalizado para errores SQL
        /// </summary>
        /// <param name="ex">Excepcion sql</param>
        /// <returns></returns>
        protected string GetErrorSqlPersonalizado(SqlException ex)
        {
            string patron1 = ".base de datos \"(.*)\", tabla \"dbo.(.*)\"";
            string patron2 = ".clave duplicada en el objeto 'dbo.(.*)' con índice único '(.*)'.";
            StringBuilder message = new StringBuilder();

            foreach (SqlError error in ex.Errors)
            {
                Match mtch1 = (new Regex(patron1)).Match(error.Message);
                Match mtch2 = (new Regex(patron2)).Match(error.Message);
                if (mtch1.Success)
                {
                    message.AppendFormat("Error en la operación SQL: el registro tiene una referencia con la tabla {0} de la base de datos {1}.", mtch1.Groups[2].Value, mtch1.Groups[1].Value);
                }
                else if (mtch2.Success)
                {
                    message.AppendFormat("Error en la operación SQL: Inserción en la tabla {0} con índice único: {1}", mtch2.Groups[1].Value, mtch2.Groups[2].Value);
                }
                else
                {
                    message.Append(error.Message);
                }
            }
            return message.ToString();
        }

        #endregion
    }

}
